<?php

namespace Pro\Support;

use Carbon\Carbon;
use Exception;

class Helper
{
    /**
     * 手机号打码
     * @param string $mobile
     * @return string
     */
    public static function maskPhoneNumber(string $mobile): string
    {
        $length = strlen($mobile);
        if ($length < 7) {
            return $mobile; // 手机号长度不够，直接返回
        }
        $start = substr($mobile, 0, 3); // 获取前三位
        $end = substr($mobile, -4); // 获取最后两位
        $mask = str_repeat('*', $length - 7); // 生成中间星号
        return $start . $mask . $end; // 拼接并返回
    }

    /**
     * 验证手机号
     * @param string $mobile
     * @return bool
     */
    public static function isMobile(string $mobile): bool
    {
        return preg_match('/^1[3-9]\d{9}$/', $mobile);
    }

    /**
     * 验证邮箱
     * @param string $email
     * @return bool
     */
    public function isEmail(string $email): bool
    {
        return filter_var($email, FILTER_VALIDATE_EMAIL);
    }

    /**
     * 身份证号码加密
     * @param string $idCard
     * @return string
     */
    public static function idCardEncode(string $idCard): string
    {
        // @todo
        return $idCard;
    }

    /**
     * 身份证号码解密
     * @param string $encodeIdCard
     * @return string
     */
    public static function idCardDecode(string $encodeIdCard): string
    {
        // @todo
        return $encodeIdCard;
    }

    /**
     * 获取身份证号性别  倒数第二位，奇数是男，偶数是女
     * @param string $idCard
     * @return int  0:未知，1:男，2:女
     */
    public static function getIdCardSex(string $idCard): int
    {
        // 处理 18 位身份证号码
        if (mb_strlen($idCard) == 18) {
            // 第 17 位为性别位
            $genderDigit = mb_substr($idCard, 16, 1);
        } elseif (mb_strlen($idCard) == 15) {
            // 第 15 位为性别位
            $genderDigit = mb_substr($idCard, 14, 1);
        } else {
            return 0;
        }

        // 判断性别位的奇偶性
        return ($genderDigit % 2 == 1) ? 1 : 2;
    }

    /**
     * 校验中国身份证号码格式（支持15位和18位）
     *
     * @param string $idCard 待校验的身份证号码
     * @return bool 校验结果，true 表示格式正确，false 表示格式错误
     */
    public static function validateIdCard(string $idCard): bool
    {
        // 去除空格并转为大写
        $idCard = strtoupper(trim($idCard));

        // 长度校验
        $length = mb_strlen($idCard);

        if ($length === 15) {
            // 15位身份证号校验
            return preg_match('/^[1-9]\d{5}\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}$/', $idCard) === 1;
        } elseif ($length === 18) {
            // 18位身份证号校验
            return self::check18DigitIdCard($idCard);
        }

        return false; // 长度不符合
    }

    /**
     * 校验18位身份证号
     * @param string $idCard
     * @return bool
     */
    public static function check18DigitIdCard(string $idCard): bool
    {
        // 正则表达式：前17位为数字，最后一位可以是数字或X
        $pattern = '/^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dX]$/';

        if (preg_match($pattern, $idCard) !== 1) {
            return false;
        }

        // 校验码验证
        $factors = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
        $checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];

        $sum = 0;
        for ($i = 0; $i < 17; $i++) {
            $sum += (int)$idCard[$i] * $factors[$i];
        }

        $mod = $sum % 11;
        $expectedCheckCode = $checkCodes[$mod];

        return $idCard[17] === $expectedCheckCode;
    }

    /**
     * 判断日期格式是否正确
     * @param string $date
     * @param string $split
     * @return bool
     */
    public static function validateDateFormat(string $date, string $split = '-'): bool
    {
        try {
            $arr = explode($split, $date);
            if (count($arr) !== 3) {
                return false;
            }

            if (mb_strlen($arr[1]) == 1) {
                $arr[1] = '0' . $arr[1];
            }

            if (mb_strlen($arr[2]) == 1) {
                $arr[2] = '0' . $arr[2];
            }

            $date = implode($split, $arr);

            $format = 'Y' . $split . 'm' . $split . 'd';
            return Carbon::createFromFormat($format, $date)->format($format) === $date;
        } catch (Exception $exception) {
            return false;
        }
    }

    /**
     * 获取ip地址
     * @return string
     */
    public static function getClientIp(): string
    {
        $ip = request()->server('HTTP_X_REAL_IP');
        if (empty($ip)) {
            $ip = request()->getClientIp();
        }

        return $ip;
    }

    /**
     * 数组转json
     * @Author : Yasin
     *
     * @param array $data
     *
     * @return string
     */
    public static function arrayToJson(array $data): string
    {
        return json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    }

    /**
     * json转数组
     * @Author : Yasin
     *
     * @param string $json
     *
     * @return array
     */
    public static function jsonToArray(string $json): array
    {
        $attachArr = json_decode($json, true);
        if (json_last_error() || empty($attachArr) || !is_array($attachArr)) {
            return [];
        }
        return $attachArr;
    }
}
